package com.demo.example;
 
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author hz
 * @Description: 测试多线程并行调用两个接口数据。
 * @create 2019-05-28
 */
public class FutureTaskTest {

    public ThreadPoolTaskExecutor defaultExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //核心线程数
        taskExecutor.setCorePoolSize(2);
        //线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        taskExecutor.setMaxPoolSize(10);
        //缓存队列
        taskExecutor.setQueueCapacity(50);
        //许的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        taskExecutor.setKeepAliveSeconds(200);
        //异步方法内部线程名称
        taskExecutor.setThreadNamePrefix("default-async-");
        /**
         * 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize，如果还有任务到来就会采取任务拒绝策略
         * 通常有以下四种策略：
         * ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
         * ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
         * ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
         * ThreadPoolExecutor.CallerRunsPolicy：重试添加当前的任务，自动重复调用 execute() 方法，直到成功
         */
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.initialize();
        // 告诉线程池，在销毁之前执行shutdown方法
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        // shutdown\shutdownNow 之后等待3秒
        taskExecutor.setAwaitTerminationSeconds(3);

        return taskExecutor;
    }

    public Map<String,String> getUserInfo() throws Exception{

        // 创建线程池
        ThreadPoolTaskExecutor threadPoolTaskExecutor = defaultExecutor();

        Map<String, String> map = new HashMap<String,String>();
        //1.获取用户基本信息
        Callable<String> userInfoCallable=new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread thread0 = Thread.currentThread();
                System.out.println("thread0启动:"+thread0.getName());
                Thread.sleep(3000);
                //模拟调用获取用户mapper接口
                return "返回用户信息数据";
            }
        };
        FutureTask<String> userInfoFutureTask = new FutureTask<>(userInfoCallable);
        threadPoolTaskExecutor.submit(userInfoFutureTask);
//       new Thread(userInfoFutureTask).start();
//        Thread thread = new Thread(userInfoFutureTask); 测试
//        thread.destroy();

        //2.获取页面展示数据信息
        Callable<String> indexDataCallable=new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread thread1 = Thread.currentThread();
                System.out.println("thread1启动:"+thread1.getName());
                Thread.sleep(5000);
                //模拟调用获取页面数据mapper接口
                return "返回页面数据信息";
            }
        };
        FutureTask<String> indexDatafutureTask = new FutureTask<>(indexDataCallable);
        threadPoolTaskExecutor.submit(indexDatafutureTask);
//        new Thread(indexDatafutureTask).start();//开启线程
 
        //3.获取对象并合并数据（调用get()方法，该线程会进入阻塞状态，直到线程返回结果才会继续执行下面代码）
        String userInfo = userInfoFutureTask.get().toString();
        map.put("userInfo",userInfo);
 
        String indexData = indexDatafutureTask.get().toString();
        map.put("indexData",indexData);

        // 销毁线程池 ，如果在springboot中 需要在整个 spring应用shutdown之前 关闭掉线程池
        threadPoolTaskExecutor.destroy();
        return map;
    }
 
    public static void main(String[] args) {
        System.out.println("主线程main："+Thread.currentThread().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
 
        System.out.println("开始"+sdf.format(new Date()));
        FutureTaskTest futureTaskTest = new FutureTaskTest();
        Map<String, String> userInfo=null;
        try {
            userInfo = futureTaskTest.getUserInfo();
            if(userInfo!=null){
                System.out.println(userInfo.get("userInfo"));
                System.out.println(userInfo.get("indexData"));
            }
            System.out.println("结束"+sdf.format(new Date()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}